﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace GenProj
{
	public class GenProjDirectory
	{
		public string DirectoryName;
		public string FolderName;
		public string Include;
		public string NoBuild;
		public string EmbeddedResource;
		public string Exclude;

		public GenProjDirectory()
		{
		}

		public GenProjDirectory(string dirName, string include, string noBuild, string embeddedResource, string exclude)
		{
			DirectoryName = dirName;
			Include = include;
			NoBuild = noBuild;
			EmbeddedResource = embeddedResource;
			Exclude = exclude;
		}

		internal void AppendProjectXML(string outputDir, StringBuilder b, List<FileInfo> usedFiles)
		{
			if (!Directory.Exists(DirectoryName))
			{
				Console.WriteLine("Unable to find directory: " + DirectoryName);
				throw new Exception();
			}

			var files = Directory.EnumerateFiles(DirectoryName, "*" , SearchOption.AllDirectories).ToArray();
			var linkDir = Path.GetFileName(DirectoryName);
			Regex exclude;
			if(string.IsNullOrWhiteSpace(Exclude))
			{
				exclude = null;
			}
			else
			{
				exclude = new Regex(Exclude);
				
			}
			Regex include;
			if(string.IsNullOrWhiteSpace(Include))
			{
				include = new Regex(".*");
			}
			else
			{
				include = new Regex(Include);
			}
			Regex nobuild;
			if(string.IsNullOrWhiteSpace(NoBuild))
			{
				nobuild = null;
			}
			else
			{
				nobuild = new Regex(NoBuild);
			}
			Regex embedded;
			if (string.IsNullOrWhiteSpace(EmbeddedResource))
			{
				embedded = null;
			}
			else
			{
				embedded = new Regex(EmbeddedResource);
			}

			foreach (var file in files)
			{
				string subFile;
				if (FolderName != null)
				{
					var index1 = file.IndexOf(linkDir);
					int index = file.IndexOf('\\', index1);
					subFile = FolderName + file.Substring(index);
				}
				else
				{
					int index = file.IndexOf(linkDir);
					subFile = file.Substring(index);
				}
				if (!include.IsMatch(file))
					continue;

				if (exclude != null && exclude.IsMatch(file))
					continue;

				if (File.Exists(file + ".ignore"))
					continue;

				FileInfo fileInfo = new FileInfo(file);
				if (File.Exists(Path.Combine(fileInfo.Directory.FullName, "genproj.ignore")))
					continue;

				string buildAction;
				if (nobuild != null && nobuild.IsMatch(file))
				{
					buildAction = "None";
				}
				else if (embedded != null && embedded.IsMatch(file))
				{
					buildAction = "EmbeddedResource";
				}
				else
				{
					buildAction = "Compile";
				}

				if (File.Exists(Path.Combine(fileInfo.Directory.FullName, "genproj.embedded")))
					buildAction = "EmbeddedResource";

				if (file[0] == '.' && file[1] == '.')
				{
					b.Append("\t\t<" + buildAction + " Include=\"" + file + "\">" + Environment.NewLine);
					b.Append("\t\t\t<Link>" + subFile + "</Link>" + Environment.NewLine);
					b.Append("\t\t</" + buildAction + ">" + Environment.NewLine);
				}
				else
				{
					b.Append("\t\t<" + buildAction + " Include=\"" + file + "\"/>" + Environment.NewLine);
				}

				usedFiles.Add(fileInfo);
			}
		}
	}

	public class GenProjProject
	{
		public List<GenProjDirectory> Directories;
		public string OutputFilename;
		public string ProjectDirectory;
		public string TemplateFilename;

		internal void GenerateProjectXML(out StringBuilder b, out List<FileInfo> usedFiles)
		{
			b = new StringBuilder();
			usedFiles = new List<FileInfo>();
			b.Append("\t<ItemGroup>" + Environment.NewLine);
			var dir = Path.GetDirectoryName(Path.GetFullPath(OutputFilename));
			foreach (var d in Directories)
			{
				d.AppendProjectXML(dir, b, usedFiles);
			}
			b.Append("\t</ItemGroup>" + Environment.NewLine);
		}
	}

	public class GenProjInput
	{
		public List<GenProjProject> Projects;
		internal void GenerateProjectXML()
		{
			var currentDir = Directory.GetCurrentDirectory();

			foreach (var proj in Projects)
			{
				Directory.SetCurrentDirectory(currentDir);
				if (proj.ProjectDirectory != null)
				{
					Directory.SetCurrentDirectory(proj.ProjectDirectory);
				}

				StringBuilder sb;
				List<FileInfo> usedFiles;
				proj.GenerateProjectXML(out sb, out usedFiles);
				var s = sb.ToString();
				var t = File.ReadAllText(proj.TemplateFilename);
				var p = t.Replace("<ProjectExtensions>GENPROJTARGETS</ProjectExtensions>", s);
				FileInfo existing = new FileInfo(proj.OutputFilename);
				if (existing.Exists)
				{
					// rename the old one just in case.
					var backupFolder = Path.Combine(existing.Directory.FullName, "GenProjBackups");
					if (!Directory.Exists(backupFolder))
					{
						Directory.CreateDirectory(backupFolder);
					}
					var backupPath = Path.Combine(backupFolder, existing.Name + "-backup-" + DateTime.Now.ToFileTimeUtc().ToString());
					File.Move(existing.FullName, backupPath);
				}
				File.WriteAllText(proj.OutputFilename, p);

				StringBuilder log = new StringBuilder();
				foreach (var file in usedFiles)
				{
					if (file.Exists)
					{
						log.AppendLine(file.FullName);
						Console.WriteLine(file.FullName);
					}
				}
				File.WriteAllText(proj.OutputFilename + ".files.log", log.ToString());
#if false
				using (var log = File.OpenWrite(proj.OutputFilename + ".files.log"))
				{
					using (var sw = new StreamWriter(log))
					{
						foreach (var file in usedFiles)
						{
							if (file.Exists)
							{
								sw.WriteLine(file.FullName);
								Console.WriteLine(file.FullName);
							}
							else
							{
								Console.WriteLine("Error: " + file.FullName);
							}
							sw.Flush();
						}
					}
				}
#endif
			}
		}
	}
}
